<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            padding-bottom: 800px;
            padding-left: 30px;
        }
    </style>
</head>

<body>
    <div id="app">
        <p>vue提供的自定义指令语法，是为开发者提供扩展DOM操作的相关接口</p>
        <h4>自定义指令的定义语法</h4>
        <ul>
            <li>
                局部指令定义 <br>
                在vue的配置选中以 directives 属性取值 对象定义自定义扩展指令 <br>
                对象中key为指令名，value为指令执行方法; 容器中通过 v-指令名 的方式完成调用
            </li>
            <li>全局(应用)指令定义 <br>
                通过createApp 方法返回的 app对象对应的全局应用方法 app.directive(key,options) 进行注册 <br>
                key 为指令名称，options的定义规则等效于局部指令的定义规则
            </li>
        </ul>
        <h4>自定义指令的对象组成</h4>
        <ul>
            <li>定义指令时，为指令提供{}参数，开启指令分段功能(生命周期功能) <br>
                <pre>
                    // 在绑定元素的 attribute 前
                    // 或事件监听器应用前调用
                    created(el, binding, vnode, prevVnode) {
                        // 下面会介绍各个参数的细节
                    },
                    // 在元素被插入到 DOM 前调用
                    beforeMount(el, binding, vnode, prevVnode) {},
                    // 在绑定元素的父组件
                    // 及他自己的所有子节点都挂载完成后调用
                    mounted(el, binding, vnode, prevVnode) {},
                    // 绑定元素的父组件更新前调用
                    beforeUpdate(el, binding, vnode, prevVnode) {},
                    // 在绑定元素的父组件
                    // 及他自己的所有子节点都更新后调用
                    updated(el, binding, vnode, prevVnode) {},
                    // 绑定元素的父组件卸载前调用
                    beforeUnmount(el, binding, vnode, prevVnode) {},
                    // 绑定元素的父组件卸载后调用
                    unmounted(el, binding, vnode, prevVnode) {}
                </pre>
            </li>
        </ul>
        <h4>自定义指令的方法参数组成</h4>
        <ul>
            <li>el:指令方法被执行时对应的DOM元素【vue虚拟DOM构建后的真实DOM元素】</li>
            <li>binding:固定为对象参数，对象中包含了指令调用时的取值、参数、修饰等其它的指令特性
                <ol>
                    <li>value: 指令=定义的取值结果(取值变化后)</li>
                    <li>oldValue: 指令=定义的取值结果(取值变化前) </li>
                    <li>arg: 指令以关键字:携带额外参数</li>
                    <li>modifiers: 指令以关键字.携带的修饰符,取值为对象=如果存在修饰符，修饰符名为对象属性名取值true;</li>
                    <li>dir: 指令的生命周期钩子函数</li>
                    <li>instance: 当前vue实例对象</li>
                </ol>
            </li>
            <li>nvnode</li>
            <li>ovnode</li>
        </ul>
        <p v-test>v-test自定义指令1</p>
        <p v-test2>v-test自定义指令1</p>

        <p v-test="color">v-test自定义指令2</p>
        <p v-test2="color">v-test自定义指令2</p>

        <p v-test:background-color="color">v-test自定义指令3</p>
        <p v-test2:background-color="color">v-test自定义指令3</p>

        <p v-test:background-color.mouseover.mouseout="color">v-test自定义指令4</p>
        <p v-test2:background-color.mouseover.mouseout="color">v-test自定义指令4</p>

        <input type="color" v-model="color">
        <p v-test:font-size.mouseover.mouseout="size">v-test自定义指令4</p>
        <p v-test2:font-size.mouseover.mouseout="size">v-test自定义指令4</p>


    </div>
    <script type="module">
        // 加载 Vue3 的ESM 模块文件
        import { createApp } from "../assets/vue3/vue.esm-browser.js"
        const app = createApp({
            data() {
                return {
                    color: "#0000ff",
                    size: "30px"
                }
            },
            directives: {
                // test:function(){}
                test(el, binding, nvnode, ovnode) {
                    console.log("el:", el);
                    console.log("binding:", binding);
                    // if(binding.value===undefined){
                    //     el.style.color="red"
                    // }else{
                    //     el.style.color=binding.value
                    // }
                    let c = binding.value === undefined ? 'red' : binding.value;
                    let s = binding.arg === undefined ? 'color' : binding.arg;
                    if (Object.keys(binding.modifiers).length == 0) {
                        el["style"][s] = c;
                    } else {
                        // for (let key in binding.modifiers) {
                        //     el.addEventListener(key,()=>{
                        //         el["style"][s] = c;
                        //     })
                        // }
                        if (binding.modifiers.mouseover) {
                            el.addEventListener("mouseover", () => {
                                el["style"][s] = c;
                            })
                        }
                        if (binding.modifiers.mouseout) {
                            el.addEventListener("mouseout", () => {
                                el["style"][s] = "";
                            })
                        }
                    }
                },
                // test:{}
            }
        });

        app.directive("test2", function (el, binding, nvnode, ovnode) {
            let c = binding.value === undefined ? 'red' : binding.value;
            let s = binding.arg === undefined ? 'color' : binding.arg;
            if (Object.keys(binding.modifiers).length == 0) {
                el["style"][s] = c;
            } else {
                if (binding.modifiers.mouseover) {
                    el.addEventListener("mouseover", () => {
                        el["style"][s] = c;
                    })
                }
                if (binding.modifiers.mouseout) {
                    el.addEventListener("mouseout", () => {
                        el["style"][s] = "";
                    })
                }
            }
        })


        app.mount("#app")
    </script>
</body>

</html>